﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Niaofei.WPF.Control
{
    public class AutoGrid : Grid
    {
        public string ColumnDefinitionsCode
        {
            get { return (string)GetValue(ColumnDefinitionsCodeProperty); }
            set { SetValue(ColumnDefinitionsCodeProperty, value); }
        }

        public static readonly DependencyProperty ColumnDefinitionsCodeProperty =
            DependencyProperty.Register("ColumnDefinitionsCode", typeof(string), typeof(AutoGrid), new PropertyMetadata(null, OnColumnDefinitionsChanged));

        private static void OnColumnDefinitionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AutoGrid grid)
            {
                var newValue = e.NewValue as string;
                if (string.Equals(newValue, e.OldValue as string, StringComparison.Ordinal))
                {
                    return;
                }

                grid.ColumnDefinitions.Clear();

                var defStrs = Regex.Split(grid.ColumnDefinitionsCode ?? "", @"[\s,]+")
                    .Where(m => !string.IsNullOrWhiteSpace(m))
                    .ToArray();

                var converter = new GridLengthConverter();

                foreach (var def in defStrs)
                {
                    if (converter.ConvertFromInvariantString(def) is GridLength gridLength)
                    {
                        var columnDef = new ColumnDefinition { Width = gridLength };
                        grid.ColumnDefinitions.Add(columnDef);
                    }
                }
            }
        }

        public string RowDefinitionsCode
        {
            get { return (string)GetValue(RowDefinitionsCodeProperty); }
            set { SetValue(RowDefinitionsCodeProperty, value); }
        }

        public static readonly DependencyProperty RowDefinitionsCodeProperty =
            DependencyProperty.Register("RowDefinitionsCode", typeof(string), typeof(AutoGrid), new PropertyMetadata(null, OnRowDefinitionsChanged));

        private static void OnRowDefinitionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AutoGrid grid)
            {
                var newValue = e.NewValue as string;
                if (string.Equals(newValue, e.OldValue as string, StringComparison.Ordinal))
                {
                    return;
                }

                grid.RowDefinitions.Clear();

                var defStrs = Regex.Split(grid.RowDefinitionsCode ?? "", @"[\s,]+")
                .Where(m => !string.IsNullOrWhiteSpace(m))
                .ToArray();

                var converter = new GridLengthConverter();

                foreach (var def in defStrs)
                {
                    if (converter.ConvertFromInvariantString(def) is GridLength gridLength)
                    {
                        var rowDef = new RowDefinition { Height = gridLength };
                        grid.RowDefinitions.Add(rowDef);
                    }
                }
            }
        }

        public bool AutoPositioning
        {
            get { return (bool)GetValue(AutoPositioningProperty); }
            set { SetValue(AutoPositioningProperty, value); }
        }

        public static readonly DependencyProperty AutoPositioningProperty =
            DependencyProperty.Register("AutoPositioning", typeof(bool), typeof(AutoGrid),
            new PropertyMetadata(true, OnAutoPositioningChanged));

        private static void OnAutoPositioningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AutoGrid grid && (bool)e.NewValue)
            {
                grid.ArrangeChildren();
            }
        }

        protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
        {
            base.OnVisualChildrenChanged(visualAdded, visualRemoved);
            if (AutoPositioning)
            {
                ArrangeChildren();
            }
        }

        protected override Size MeasureOverride(Size constraint)
        {
            if (AutoPositioning && IsLoaded)
            {
                ArrangeChildren();
            }
            return base.MeasureOverride(constraint);
        }

        private void ArrangeChildren()
        {
            var columnCount = this.ColumnDefinitions.Count;
            if (columnCount == 0)
            {
                columnCount = 1;
            }

            var index = 0;
            foreach (UIElement child in Children)
            {
                if (child == null)
                {
                    continue;
                }

                var row = index / columnCount;
                var column = index % columnCount;

                if (GetRow(child) != row)
                {
                    SetRow(child, row);
                }

                if (GetColumn(child) != column)
                {
                    SetColumn(child, column);
                }

                index++;
            }
        }
    }
}
